//
// Created by songpingwang on 25-7-13.
//

#ifndef ZDATAVIEW_INL
#define ZDATAVIEW_INL
#include "UDataView.h"

namespace NDFrame {
    //////////////////////////////////////////////////////////////////////////////
    ////					对应字段值： 对df.txt df.txt_sep进行字符拼接
    //////////////////////////////////////////////////////////////////////////////

    template<Field field>
    std::string UDataView::join(const std::string_view separator) const {
        using FieldType = std::remove_reference_t<decltype(std::declval<const DataItem>().ValueField<field>())>;
        static_assert(std::is_same_v<FieldType, std::string>, "join() can only be applied to string fields.");

        if (this->empty()) {
            return {};
        }

        if (m_size == 1) {
            return getTextRefConst<field>(m_dataPtr[0]);
        }

        size_t totalLength = 0;
        if (this->m_size > 1) {
            totalLength += (this->m_size - 1) * separator.size();
        }
        for (size_t i = 0; i < this->m_size; ++i) {
            totalLength += m_dataPtr[i].ValueField<field>().length();
        }

        std::string result;
        result.reserve(totalLength);
        result.append(m_dataPtr[0].ValueField<field>());

        for (size_t i = 1; i < this->m_size; ++i) {
            result.append(separator);
            result.append(m_dataPtr[i].ValueField<field>());
        }

        return result;
    }


    /////////////////////////////////////////////////////////////////////////////////////////
    ////             对应字段值： 对df.txt df.txt_sep进行字符拼接并替换字符(oldChar->newChar)
    /////////////////////////////////////////////////////////////////////////////////////////

    template<Field field>
    std::string UDataView::join_and_replace(
        const char oldChar,
        const std::string_view newChars,
        const std::string_view separator) const {
        using FieldType = std::remove_reference_t<decltype(std::declval<const DataItem>().ValueField<field>())>;
        static_assert(std::is_same_v<FieldType, std::string>,
                      "join_and_replace() can only be applied to string fields.");

        if (this->empty()) {
            return {};
        }

        std::string result;
        result.reserve(this->size() * 16); // 预留一个合理的初始大小

        bool first = true;
        for (size_t i = 0; i < this->m_size; ++i) {
            if (!first && !separator.empty()) {
                result.append(separator);
            }
            const std::string &source_str = m_dataPtr[i].ValueField<field>();
            for (const char c: source_str) {
                if (c == oldChar) {
                    result.append(newChars);
                } else {
                    result.push_back(c);
                }
            }
            first = false;
        }

        return result;
    }


    //////////////////////////////////////////////////////////////////////////////
    ////      对应字段值： 对df.txt df.txt_sep是否在vector<field>容器内
    //////////////////////////////////////////////////////////////////////////////
    template<Field field>
    bool UDataView::is_in(const std::vector<std::string> &txts, VecItemPtr &out_pointers) const {
        out_pointers.clear();

        for (size_t i = 0; i < m_size; ++i) {
            const auto &str_raw = getTextRefConst<field>(m_dataPtr[i]);
            if (std::find(txts.begin(), txts.end(), str_raw) != txts.end()) {
                out_pointers.push_back(&m_dataPtr[i]);
            }
        }
        return !out_pointers.empty();
    }


    //////////////////////////////////////////////////////////////////////////////
    ////				   通用函数 对应字段值进行过滤
    //////////////////////////////////////////////////////////////////////////////
    template<typename Predicate>
    bool UDataView::filter(VecItemPtr &out_pointers, Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem &>,
                      "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");

        out_pointers.clear();
        if (this->empty()) {
            return false;
        }

        out_pointers.reserve(this->size());
        for (size_t i = 0; i < this->m_size; ++i) {
            if (predicate(m_dataPtr[i])) {
                out_pointers.push_back(&m_dataPtr[i]);
            }
        }
        return !out_pointers.empty();
    }


    //////////////////////////////////////////////////////////////////////////////
    ////				   通用函数 对应字段值进行过滤(返回dataframe副本)
    //////////////////////////////////////////////////////////////////////////////
    template<typename Predicate>
    UDataFrame UDataView::DF_filter(Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem &>,
                      "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");

        UDataFrame result;
        if (this->empty()) {
            return result;
        }
        result.reserve(this->size());
        for (size_t i = 0; i < this->m_size; ++i) {
            if (predicate(m_dataPtr[i])) {
                result.push_back(m_dataPtr[i]);
            }
        }
        return result;
    }


    //////////////////////////////////////////////////////////////////////////////
    ////			   专用函数 对应字段值进行过滤--返回df副本（深复制）
    //////////////////////////////////////////////////////////////////////////////

    template<Field field, typename Comparator>
    UDataFrame UDataView::DF_reg_len_cmp_v(
        const RE2::Set &regex_set,
        size_t len,
        Comparator compare) const {
        using FieldType = std::remove_reference_t<decltype(std::declval<const DataItem>().ValueField<field>())>;
        static_assert(std::is_same_v<FieldType, std::string>, "This function can only be applied to string fields.");
        static_assert(std::is_invocable_r_v<bool, Comparator, size_t, size_t>,
                      "Comparator must be callable with two size_t and return bool.");

        UDataFrame result;
        if (this->empty()) {
            return result;
        }
        result.reserve(this->size());

        for (size_t i = 0; i < this->m_size; ++i) {
            const std::string &field_value = m_dataPtr[i].ValueField<field>();
            if (compare(field_value.length(), len) && regex_set.Match(field_value, nullptr)) {
                result.push_back(m_dataPtr[i]);
            }
        }
        return result;
    }


    template<Field field, typename Predicate>
    UDataFrame UDataView::DF_reg_cond_v(
        const RE2::Set &regex_set, Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem&>,
            "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");
        UDataFrame result(m_size > 3 ? 3 : m_size);
        if (m_size == 0) { return result; }

        for (size_t i = 0; i < m_size; ++i) {
            if (!predicate(m_dataPtr[i])) { continue; }
            if (regex_set.Match(m_dataPtr[i].ValueField<field>(), nullptr)) {
                result.push_back(m_dataPtr[i]);
            }
        }
        return result;
    }


    template<Field field>
    UDataFrame UDataView::DF_reg_impl_v(const RE2::Set &regex_set) const {
        UDataFrame result(m_size > 3 ? 3 : m_size);
        if (m_size == 0) { return result; }

        for (size_t i = 0; i < m_size; ++i) {
            if (regex_set.Match(m_dataPtr[i].ValueField<field>(), nullptr)) {
                result.push_back(m_dataPtr[i]);
            }
        }
        return result;
    }


    template<Field field>
    UDataFrame UDataView::DF_reg_impl_v(const RE2 &regex_) const {
        UDataFrame result(m_size > 3 ? 3 : m_size);
        if (m_size == 0) { return result; }

        for (size_t i = 0; i < m_size; ++i) {
            if (RE2::PartialMatch(m_dataPtr[i].ValueField<field>(), regex_)) {
                result.push_back(m_dataPtr[i]);
            }
        }
        return result;
    }

    template<typename Predicate>
    UDataFrame UDataView::DF_xyxy_impl_v(Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem&>,
            "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");

        UDataFrame result(m_size > 3 ? 3 : m_size);
        for (size_t i = 0; i < m_size; ++i) {
            if (predicate(m_dataPtr[i])) {
                result.push_back(m_dataPtr[i]);
            }
        }
        return result;
    }


    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    ///						 UDataView 类的过滤函数		                ////
    ////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////


    template<Field field>
    bool UDataView::ptr_reg_impl_v(VecItemPtr &out_ptr, const RE2::Set &regex_set) const {
        if (out_ptr.empty()) { out_ptr.reserve(3); }

        for (size_t i = 0; i < m_size; ++i) {
            if (regex_set.Match(m_dataPtr[i].ValueField<field>(), nullptr)) {
                out_ptr.push_back(&m_dataPtr[i]);
            }
        }
        return !out_ptr.empty();
    }


    template<Field field, typename Predicate>
    bool UDataView::ptr_reg_len_cond_v(
        VecItemPtr &out_ptr,
        const RE2::Set &regex_set, const int len, Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem&>,
            "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");
        if (out_ptr.empty()) { out_ptr.reserve(3); }

        for (size_t i = 0; i < m_size; ++i) {
            const std::string &field_value = m_dataPtr[i].ValueField<field>();
            if (predicate(field_value.size(), len) && regex_set.Match(field_value, nullptr)) {
                out_ptr.push_back(&m_dataPtr[i]);
            }
        }
        return !out_ptr.empty();
    }


    template<Field field, typename Predicate>
    bool UDataView::ptr_reg_len_cond_v(
        VecItemPtr &out_ptr,
        const RE2 &regex_, const int len, Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem&>,
            "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");
        if (out_ptr.empty()) { out_ptr.reserve(3); }

        for (size_t i = 0; i < m_size; ++i) {
            const std::string &field_value = m_dataPtr[i].ValueField<field>();
            if (predicate(field_value.size(), len) && RE2::PartialMatch(field_value, regex_)) {
                out_ptr.push_back(&m_dataPtr[i]);
            }
        }
        return !out_ptr.empty();
    }


    template<Field field, typename Predicate>
    bool UDataView::ptr_reg_cond_v(VecItemPtr &out_ptr, const RE2 &regex_, Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem&>,
            "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");
        if (out_ptr.empty()) { out_ptr.reserve(3); }

        for (size_t i = 0; i < m_size; ++i) {
            if (predicate(m_dataPtr[i]) && RE2::PartialMatch(m_dataPtr[i].ValueField<field>(), regex_)) {
                out_ptr.push_back(&m_dataPtr[i]);
            }
        }
        return !out_ptr.empty();
    }


    template<Field field, typename Predicate>
    bool UDataView::ptr_reg_cond_v(VecItemPtr &out_ptr, const RE2::Set &regex_set, Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem&>,
            "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");
        if (out_ptr.empty()) { out_ptr.reserve(3); }

        for (size_t i = 0; i < m_size; ++i) {
            if (predicate(m_dataPtr[i]) && regex_set.Match(m_dataPtr[i].ValueField<field>(), nullptr)) {
                out_ptr.push_back(&m_dataPtr[i]);
            }
        }
        return !out_ptr.empty();
    }



    template<typename Predicate>
    bool UDataView::ptr_xyxy(VecItemPtr& out_ptr, Predicate predicate) const {
        static_assert(std::is_invocable_r_v<bool, Predicate, const DataItem &>,
              "Predicate must be a callable that takes 'const DataItem&' and returns 'bool'.");
        if (out_ptr.empty()) { out_ptr.reserve(3); }

        for (size_t i = 0; i < m_size; ++i) {
            if (predicate(m_dataPtr[i])) {
                out_ptr.push_back(&m_dataPtr[i]);
            }
        }

        return !out_ptr.empty();
    }
}

#endif
